<?php
/**
 * Created by paperphp
 * User: 22071
 * Date: 2019/6/21
 * Email: <zhendongdong@foxmail.com>
 */

namespace paper\database;


use ArrayAccess;
use Iterator;
use paper\Paginate;
use paper\support\model;

class Collection implements Iterator, ArrayAccess
{
    private $data = [];
    /* @var Paginate $paginate */
    private $paginate = null;
    private $is_model_data = false;

    public function __construct(&$data, $is_model_data = false)
    {
        $this->data          = &$data;
        $this->is_model_data = $is_model_data;
    }


    /**
     * 检测当前是否为空数据集
     * @return bool
     */
    public function isEmpty(): bool
    {
        return $this->data ? false : true;
    }

    /**
     * 检测当前是否为空数据集
     * @return bool
     */
    public function isNotEmpty(): bool
    {
        return $this->data ? true : false;
    }

    /**
     * @param $paginate
     * @return null
     */
    public function setPaginate($paginate)
    {
        return $this->paginate = $paginate;
    }


    /**
     * 暂时尚未实现
     * @param $field
     */
    public function columns($field)
    {

    }


    /**
     * 获取数据的键值
     * @return array
     */
    public function keys()
    {
        return array_keys($this->data);
    }

    /**
     * 遍历数组并且调用回调函数
     * @param \Closure $closure
     * @return array
     */
    public function map(\Closure $closure)
    {
        return array_map($closure, $this->data);
    }

    /**
     * 转换书组
     * @return array
     */
    public function toArray()
    {
        if ($this->is_model_data) {
            return array_map(function ($value) {
                /* @var $value Model */
                return $value->toArray();
            }, $this->data);
        }
        return $this->data;
    }

    /**
     *=======================================================================
     *
     *  以下为实现的接口
     *
     *========================================================================
     */

    /**
     * Return the current element
     * @link https://php.net/manual/en/iterator.current.php
     * @return mixed Can return any type.
     * @since 5.0.0
     */
    public function current()
    {
        $data = current($this->data);
        return $data;
    }

    /**
     * Move forward to next element
     * @link https://php.net/manual/en/iterator.next.php
     * @return void Any returned value is ignored.
     * @since 5.0.0
     */
    public function next()
    {
        $data = next($this->data);
        return $data;
    }

    /**
     * Return the key of the current element
     * @link https://php.net/manual/en/iterator.key.php
     * @return mixed scalar on success, or null on failure.
     * @since 5.0.0
     */
    public function key()
    {
        return key($this->data);
    }

    /**
     * @return bool
     */
    public function valid()
    {
        return key($this->data) !== null;
    }

    /**
     *
     */
    public function rewind()
    {
        reset($this->data);
    }

    /**
     * @return false|string
     */
    public function __toString()
    {
        if ($this->paginate) {
            return $this->paginate->render();
        }
        return json_encode($this->data);
    }

    /**
     * Whether a offset exists
     * @link https://php.net/manual/en/arrayaccess.offsetexists.php
     * @param mixed $offset <p>
     * An offset to check for.
     * </p>
     * @return boolean true on success or false on failure.
     * </p>
     * <p>
     * The return value will be casted to boolean if non-boolean was returned.
     * @since 5.0.0
     */
    public function offsetExists($offset)
    {
        return isset($this->data[$offset]);
    }

    /**
     * Offset to retrieve
     * @link https://php.net/manual/en/arrayaccess.offsetget.php
     * @param mixed $offset <p>
     * The offset to retrieve.
     * </p>
     * @return mixed Can return all value types.
     * @since 5.0.0
     */
    public function offsetGet($offset)
    {
        return $this->data[$offset];
    }

    /**
     * Offset to set
     * @link https://php.net/manual/en/arrayaccess.offsetset.php
     * @param mixed $offset <p>
     * The offset to assign the value to.
     * </p>
     * @param mixed $value <p>
     * The value to set.
     * </p>
     * @return void
     * @since 5.0.0
     */
    public function offsetSet($offset, $value)
    {
        $this->data[$offset] = $value;
    }

    /**
     * Offset to unset
     * @link https://php.net/manual/en/arrayaccess.offsetunset.php
     * @param mixed $offset <p>
     * The offset to unset.
     * </p>
     * @return void
     * @since 5.0.0
     */
    public function offsetUnset($offset)
    {
        unset($this->data[$offset]);
    }
}